﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MP3Ganizer.BusinessObject.Infos;
using System.IO;
using TagLib;
using System.Collections.ObjectModel;
using MP3Ganizer.BusinessObject.Services.Common;

namespace MP3Ganizer.BusinessObject.Services.IO
{
    public class FileService : MP3Ganizer.BusinessObject.Services.IO.IFileService
    {
        private string[] MUSIC_MANAGED_TYPE = new string[] {"mp3", "wma"};
        private string[] IMG_MANAGED_TYPE = new string[] { "jpeg", "jpg", "bmp", "gif" };

        private Dictionary<string, string[]> _imagesStates;



        public IServiceResult GetMP3InfosFromDirectory(string directory, ObservableCollection<MP3Infos> list)
        {
            if (list == null)
                return new ServiceFailure("Erreur interne du service.");
            try
            {
                _imagesStates = new Dictionary<string, string[]>();
                IEnumerable<string> files = MUSIC_MANAGED_TYPE.SelectMany(t => Directory.EnumerateFiles(directory, string.Format("*.{0}", t), SearchOption.AllDirectories));
                files.ToList().ForEach(file => list.Add(CreateInfoFromFile(file)));
            }
            catch (Exception e)
            {
                return new ServiceFailure("Erreur lors de la chargement du répertoire", e.Message);

            }
            return new ServiceSuccess();

        }
        public IEnumerable<MP3Infos> GetMP3InfosFromDirectory(string directory)
        {
            IEnumerable<string> files = MUSIC_MANAGED_TYPE.SelectMany(t => Directory.EnumerateFiles(directory, string.Format("*.{0}", t), SearchOption.AllDirectories));
            return files.Select(file => CreateInfoFromFile(file));
        }
        private MP3Infos CreateInfoFromFile(string file)
        {
            try
            {
                var tagfile = TagLib.File.Create(file);

                IEnumerable<string> artists = tagfile.Tag.Performers.AsEnumerable().OrderBy(a => a);
                if (string.IsNullOrEmpty(tagfile.Tag.FirstPerformer) && !string.IsNullOrEmpty(tagfile.Tag.FirstAlbumArtist))
                    artists = tagfile.Tag.AlbumArtists.AsEnumerable().OrderBy(a => a);
                if (artists == null)
                    artists = DefaultValues.Artistes;

                string album = tagfile.Tag.Album;
                if (string.IsNullOrEmpty(album ))
                    album = DefaultValues.Album;

                string title = tagfile.Tag.Title;
                if (string.IsNullOrEmpty(title))
                    title = System.IO.Path.GetFileNameWithoutExtension(file);
                if (string.IsNullOrEmpty(title))
                    title = DefaultValues.Title;

                int track = (int)tagfile.Tag.Track;

                string[] images = GetImagesFromFileDirectory(file);

                return new MP3Infos(artists, album, title, track, file, images);
            }
            catch
            {
                return new MP3Infos(DefaultValues.Artistes, DefaultValues.Album, DefaultValues.Title, 0, file, DefaultValues.Images); 
            }
        }

        private string[] GetImagesFromFileDirectory(string file)
        {
            var directory = new FileInfo(file).Directory;

            if (_imagesStates.ContainsKey(directory.FullName))
                return _imagesStates[directory.FullName];
            else
            {
                string[] images = new string[0];
                IMG_MANAGED_TYPE.ToList().ForEach(item => images = images.Concat(directory.GetFiles(string.Format("*.{0}", item)).Select(f => f.FullName)).ToArray());
                _imagesStates.Add(directory.FullName, images);
                return images;
            }
        }
        public bool TryToApplySettings(IEnumerable<MP3Infos> infos, string directory, out IEnumerable<MP3Infos> withProblem)
        {
            IEnumerable<MP3Infos> mayHaveProblem = new MP3Infos[0].AsEnumerable();
            IEnumerable<MP3Infos> modified = new MP3Infos[0].AsEnumerable();

            bool success = infos.All(info => TryToCopyAndDelete(info, directory, modified, mayHaveProblem));

            success = success && modified.All(info => TryToUpdate(info, modified, mayHaveProblem));

            withProblem = mayHaveProblem;

            return success;
        }
        private bool TryToUpdate(MP3Infos info, IEnumerable<MP3Infos> modified, IEnumerable<MP3Infos> mayHaveProblem)
        {
            try
            {
                var tagFile = TagLib.File.Create(info.SourcePath);

                tagFile.Tag.Album = info.Album;
                tagFile.Tag.Performers = info.Artists.ToArray();
                tagFile.Tag.Title = info.Title;
                tagFile.Tag.Track = (uint)info.TrackNumber;
                tagFile.Save();
                
                modified.Concat(new MP3Infos[1] { info }.AsEnumerable());
                return true;
            }
            catch
            {
                mayHaveProblem.Concat(new MP3Infos[1] { info }.AsEnumerable());
                return false;
            }   
        }
        private bool TryToCopyAndDelete(MP3Infos info, string directory, IEnumerable<MP3Infos> modified, IEnumerable<MP3Infos> mayHaveProblem)
        {
            try
            {
                string fileName = string.Format("{1} - {0}", info.Title, info.TrackNumber);
                string filePath = System.IO.Path.Combine(directory, fileName);

                System.IO.File.Copy(info.SourcePath, filePath);
                System.IO.File.Delete(info.SourcePath);

                modified.Concat(new MP3Infos[1] { info.ChangeSourcePath(filePath)}.AsEnumerable());

                return true;
            }
            catch
            {
                mayHaveProblem.Concat(new MP3Infos[1] { info }.AsEnumerable());
                return false;
            }   
        }
    }
}
